#include <Core/SearchEngine/SearchEngine.h>

namespace Core {

void SearchEngine::runArrayLoading( Common::IInputDevicePtr const inputDevice
	, boost::int64_t from, size_t bufsize )
{
	if (buffer.size() > m_keyMaxLength) {
		size_t pos = buffer.size() - m_keyMaxLength;
		buffer.assign(buffer.substr(pos));
	}
	loadArray(inputDevice, from, bufsize);

}

void SearchEngine::findSignature(
	Common::IInputDevicePtr const searchTraits, IKeyValueStoragePtr const keyValueStorageImpl, std::string& sign)
{
	std::string nextKey;
	std::size_t count = keyValueStorageImpl->getKeyCount();
	try
	{
		for (std::size_t i = 0; i < count; ++i) {
			keyValueStorageImpl->getKey(nextKey, i);
			if (buffer.find(nextKey) != std::string::npos) {
				sign.assign(nextKey);
				break;
			}
		}
	}
	catch(std::exception const & /*expt*/)
	{
		sign.clear();
	}
}

void SearchEngine::loadArray(
	Common::IInputDevicePtr const inputDeviceImpl, boost::int64_t from, size_t size)
{
	char buf[BUF_SIZE] = { 0 };
	size_t bytesCount = 0;
	try
	{
		bytesCount = inputDeviceImpl->readBlock( buf, from, from + size );
	}
	catch (const Common::InputDeviceException& /*ex*/ )
	{
	}
	buffer.append(buf, bytesCount);
}

SearchEngine::SearchEngine() 
	: m_keyMaxLength(0)
	, buffer()
{ 
}

SearchEngine::~SearchEngine() 
{ 
}

std::string SearchEngine::searchStart(
	Common::IInputDevicePtr const inputDeviceImpl, IKeyValueStoragePtr const keyValueStorageImpl)
{
	int64_t length = inputDeviceImpl->expectedSize();
	m_keyMaxLength = keyValueStorageImpl->getKeyMaxLength();
	int64_t cycleCount = (length / BUF_SIZE) + 1;
	int64_t from = 0;
	std::string guid;
	
	for (int64_t i = 0 ; i < cycleCount; ++i, from += BUF_SIZE) {
		std::string sign;
		runArrayLoading(inputDeviceImpl, from, BUF_SIZE);
		findSignature(inputDeviceImpl, keyValueStorageImpl, sign );
		if (!sign.empty()) {
			KeyBucket bucket;
			keyValueStorageImpl->getBucket(sign, bucket);
			guid.assign(bucket.GUID);
			break;
		}
	}
	return guid;
}

} // namespace Core

